#ifndef TERRAIN_GUARDING_H
#define TERRAIN_GUARDING_H



/*

Terrain Guarding solver


*/


#include <iostream>
#include <fstream>
#include <cmath>
#include <assert.h>

#include <DataTypes.h>
#include <GK_PC_solver.h>
#include <tinythread.h>
#include <fast_mutex.h>



#if __CUDACC__
#include <cuGK_PC_solver.h>

#endif


#define NOT_SET -1
#define INT_INFITY 10000

#define USE_THREADS 1



// user types
typedef unsigned int uint;


typedef enum _pt_type {POINT, GUARD, POINT_GUARD} pt_type;
typedef enum _inst_type {GUARDING, WEIGHT_GUARD, MULTI_GUARD, WEIGHT_MULTI_GUARD} inst_type;
typedef enum _input_mode {ILP, GEOMETRIC} input_mode;
typedef enum _status_code {ROUND_FIN,FIN,LP_SOL,LP_NON_SOL,FOUND_SOL} status_code;




class TGInstance
{
	public:
	 TGInstance(){};
	 TGInstance(std::string&, input_mode);
	

	 // visibility methods
	 bool& update_visible(index p, index q);
	 bool visible(index p, index q) const;
	 bool left_visible(index p, index q) const;
	 bool right_visible(index p, index q) const;

	// interface methods
	input_mode getInputType() const;
	inst_type getInstType() const;
	size_t num_guards() const;
	size_t num_points() const;
	real demand(index p);
	real weight(index g);
 


         
	protected:
	  matrix<bool> V;
	  vector<real> weights;
	  vector<real> demands;

	  size_t _num_guards;
      size_t _num_points;
      inst_type instance_type;
	  input_mode input_type; 
	  long D; // number of non-negative elements

	friend std::ostream& operator << (std::ostream& out, const TGInstance& T);
     	friend class TGSolver;
	
};




class TGSolver
{
	public:
	 TGSolver(TGInstance&, dreal omega);

	 // interface methods
	 dreal total_cost() const;

	 

	protected:
	  status_code LPSolver(dreal);
	  status_code RoundGuards(dreal);
	  status_code LeftGuarding();
	  status_code RightGuarding();

	  // auxillary methods
	  void decompose(index, vector<dreal>&, dreal&, dreal&);
	  
	  // algorithm specific data
	  vector<index> left_demand;
	  vector<index> right_demand;
	  dreal cost;	
	  vector<dreal> cover_sol;
	  
	  // solution
	  vector<bool> guards;

	  TGInstance& T;         	 
	  dreal omega; // approximate error	   
	  integer d_min;

	  // info 
	  Timer compute_time;
	  	
};


class Arg
{
	public:
		Arg(TGInstance& T,vector<index>& demand, vector<bool>& guards, dreal& cost, tthread::fast_mutex& mutex);
		
		TGInstance &T;
		vector<index>& demand;
		vector<bool>& guards; // enable mutex on this
		dreal& cost; // cost value
		tthread::fast_mutex& mutex;
		
};


void LeftGuardingThreadCode(void *args);

void RightGuardingThreadCode(void *arg);






#endif
